/*
 * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.js.test.klib

import org.jetbrains.kotlin.js.test.runners.AbstractJsBlackBoxCodegenTestBase.JsBackendFacades
import org.jetbrains.kotlin.js.test.runners.commonConfigurationForJsBackendSecondStageTest
import org.jetbrains.kotlin.js.test.runners.configureJsBoxHandlers
import org.jetbrains.kotlin.js.test.runners.setUpDefaultDirectivesForJsBoxTest
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.test.FirParser
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives.WITH_STDLIB
import org.jetbrains.kotlin.test.klib.CustomKlibCompilerFirstStageTestSuppressor
import org.jetbrains.kotlin.test.klib.CustomKlibCompilerTestSuppressor
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JsFirstStageEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsSourceFilesProvider
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
import org.jetbrains.kotlin.utils.bind
import org.junit.jupiter.api.Tag

@Tag("custom-first-stage")
open class AbstractCustomJsCompilerFirstStageTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JS_IR) {
    override fun configure(builder: TestConfigurationBuilder) = with(builder) {
        globalDefaults {
            // Note: Need to specify the concrete FE kind because this affects the choice of IGNORE_BACKEND_* directive.
            frontend = if (customJsCompilerSettings.defaultLanguageVersion.usesK2) FrontendKinds.FIR else FrontendKinds.ClassicFrontend
            targetPlatform = JsPlatforms.defaultJsPlatform
            dependencyKind = DependencyKind.Binary
        }
        defaultDirectives {
            // `js-ir-minimal-for-test` must not be used in this test at all, so need to use `kotlin-test` library on 2nd stage via `WITH_STDLIB` directive
            // Note: on 1st stage, compilation is done against not `js-ir-minimal-for-test` (it's not bundled to stdlib Maven artifact),
            // but against `kotlin-test` library, which has assert functions of different signatures.
            // So, an attempt to use `js-ir-minimal-for-test` on 2nd stage will cause unresolved symbols like `kotlin.test/assertEquals|assertEquals(0:0;0:0;kotlin.String?){0§<kotlin.Any?>}[0]`
            +WITH_STDLIB
        }

        useConfigurators(
            ::CommonEnvironmentConfigurator,
            ::JsFirstStageEnvironmentConfigurator,
            // And this configurator is necessary to relax the second compilation stage, since the old compiler could produce IR
            // which would not pass new improved IR validation rules
            ::CustomWebCompilerSecondStageEnvironmentConfigurator,
        )

        useAdditionalSourceProviders(
            ::CoroutineHelpersSourceFilesProvider,
            ::AdditionalDiagnosticsSourceFilesProvider,
        )

        facadeStep(::CustomWebCompilerFirstStageFacade)

        useAfterAnalysisCheckers(
            // Suppress all tests that have not been successfully compiled by the first stage.
            // And the limited number of tests where KLIBs generated by a specific compiler version
            // are known to have some problems that cause crash on the second stage.
            ::CustomKlibCompilerFirstStageTestSuppressor.bind(customJsCompilerSettings.defaultLanguageVersion),

            // Suppress all tests that failed on the second stage if they are anyway marked as "IGNORE_BACKEND*".
            ::CustomKlibCompilerTestSuppressor,
        )

        commonConfigurationForJsBackendSecondStageTest(
            pathToTestDir = "compiler/testData/codegen/box/",
            testGroupOutputDirPrefix = "customJsCompilerFirstStageTest/",
            backendFacades = JsBackendFacades.WithRecompilation
        )

        setUpDefaultDirectivesForJsBoxTest(parser = /* Does not matter */ FirParser.LightTree)

        configureJsBoxHandlers()
    }
}
